Skip to content

[Refactor] : J-POP 번역 dbArtistKoMap 초기화를 DB 직접 조회로 변경 (#199)#200

Merged
GulSam00 merged 1 commit into
developfrom
refactor/199-refactorDbArtistKoMapInit
Apr 19, 2026
Merged

[Refactor] : J-POP 번역 dbArtistKoMap 초기화를 DB 직접 조회로 변경 (#199)#200
GulSam00 merged 1 commit into
developfrom
refactor/199-refactorDbArtistKoMapInit

Conversation

@GulSam00
Copy link
Copy Markdown
Owner

@GulSam00 GulSam00 commented Apr 19, 2026

User description

📌 PR 제목

[Refactor] : J-POP 번역 dbArtistKoMap 초기화를 DB 직접 조회로 변경

📌 변경 사항

  • @/supabase/getDBgetArtistKoMapDB() 추가
    • tag_id=101 + artist_ko IS NOT NULL 로 distinct artist→artist_ko 를 DB 에서 직접 로드
    • first-seen 원칙(Map 중복 시 덮어쓰지 않음)으로 Map 구성
  • translationJpn.ts:
    • 배치 내 빈도 집계(artistKoCountMap) 로직 전부 제거
    • dbArtistKoMap 초기화를 getArtistKoMapDB() 호출로 단일화
    • 번역 성공 경로에서 if (!has) set(finalArtistKo) 로 런타임 맵 동기화 (alias/DB/AI 공통)
    • [DB] 로그 prefix 및 usedDbArtist 카운터 분리 추가

💬 추가 참고 사항


PR Type

Enhancement


Description

  • Refactor dbArtistKoMap initialization to query DB directly instead of batch-based aggregation

  • Add getArtistKoMapDB() function to load artist translations from database

  • Implement runtime map synchronization with first-seen principle

  • Separate logging and metrics for DB-sourced artist translations


Diagram Walkthrough

flowchart LR
  A["getArtistKoMapDB()"] -->|"Load all J-POP artist_ko"| B["dbArtistKoMap"]
  B -->|"Priority 1: Check alias"| C["aliasArtistKo"]
  B -->|"Priority 2: Check DB"| D["dbArtistKo"]
  E["AI Translation"] -->|"Priority 3: Fallback"| F["finalArtistKo"]
  C -->|"Use if exists"| F
  D -->|"Use if exists"| F
  F -->|"Sync runtime map"| B
  B -->|"Maintain consistency"| G["Updated Songs"]
Loading

File Walkthrough

Relevant files
Enhancement
translationJpn.ts
Integrate DB artist map and implement priority-based translation

packages/crawling/src/cron/translationJpn.ts

  • Import getArtistKoMapDB function for database-driven initialization
  • Add usedDbArtist counter to track DB-sourced translations
  • Initialize dbArtistKoMap by calling getArtistKoMapDB() before
    processing
  • Implement three-tier priority for artist translation: alias → DB → AI
  • Add runtime map synchronization using first-seen principle (no
    overwrite)
  • Separate log prefixes for alias [ALIAS], DB [DB], and AI [OK]
    translations
  • Update results summary to display DB-sourced translation count
+25/-4   
getDB.ts
Add database function to load artist translation map         

packages/crawling/src/supabase/getDB.ts

  • Add new getArtistKoMapDB() function to fetch J-POP songs with non-null
    artist_ko
  • Query filters: tag_id=101 (J-POP) and artist_ko IS NOT NULL
  • Build Map using first-seen principle to ensure single artist_ko per
    artist
  • Return Map for efficient artist-to-translation lookup
+24/-0   

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
singcode Ready Ready Preview, Comment Apr 19, 2026 2:30pm

@GulSam00
Copy link
Copy Markdown
Owner Author

/describe

@GulSam00
Copy link
Copy Markdown
Owner Author

/review

@GulSam00
Copy link
Copy Markdown
Owner Author

/improve

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 19, 2026

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

Refactor J-POP artist translation to use direct DB lookup

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Refactor dbArtistKoMap initialization to query DB directly instead of batch-based aggregation
• Add new getArtistKoMapDB() function to load artist translations from database
• Implement three-tier priority for artist translation: alias > DB > AI
• Add separate counter and log prefix for DB-sourced artist translations
• Synchronize runtime map with successful translations using first-seen principle
Diagram
flowchart LR
  A["getArtistKoMapDB()"] -->|Load from DB| B["dbArtistKoMap"]
  C["artistAlias"] -->|Priority 1| D["finalArtistKo"]
  B -->|Priority 2| D
  E["AI Translation"] -->|Priority 3| D
  D -->|Update DB| F["Song Record"]
  D -->|Sync Runtime| B
Loading

Grey Divider

File Changes

1. packages/crawling/src/cron/translationJpn.ts ✨ Enhancement +25/-4

Integrate DB artist map and implement priority-based translation

• Import new getArtistKoMapDB() function from supabase module
• Initialize dbArtistKoMap by calling getArtistKoMapDB() at start of batch
• Implement three-tier artist translation priority: alias > DB > AI
• Add usedDbArtist counter to track DB-sourced translations separately
• Add log prefix differentiation: [ALIAS], [DB], [OK] for different translation sources
• Synchronize runtime map with successful translations using first-seen logic
• Update results log output to include DB-sourced translation count

packages/crawling/src/cron/translationJpn.ts


2. packages/crawling/src/supabase/getDB.ts ✨ Enhancement +24/-0

Add function to load artist translations from database

• Add new getArtistKoMapDB() function to query J-POP songs with existing translations
• Query songs with tag_id=101 and non-null artist_ko from database
• Build Map using first-seen principle to ensure single translation per artist
• Return Map<string, string> mapping artist names to Korean translations

packages/crawling/src/supabase/getDB.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 19, 2026

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Non-deterministic artist_ko pick 🐞 Bug ≡ Correctness
Description
getArtistKoMapDB()는 Map에 first-seen으로 artist_ko를 고정하지만 쿼리에 ORDER BY가 없어 동일 artist에 여러 artist_ko가 존재할
때 어떤 값이 선택될지 실행마다 달라질 수 있습니다. 이 값은 translationJpn.ts에서 AI 결과를 덮어써 artist_ko 재사용 일관성을 깨뜨릴 수 있습니다.
Code

packages/crawling/src/supabase/getDB.ts[R121-135]

+  const { data, error } = await supabase
+    .from('songs')
+    .select('artist, artist_ko, song_tags!inner(tag_id)')
+    .eq('song_tags.tag_id', 101)
+    .not('artist_ko', 'is', null)
+    .limit(50000);
+
+  if (error) throw error;
+
+  const map = new Map<string, string>();
+  for (const row of data) {
+    if (!row.artist || !row.artist_ko) continue;
+    if (!map.has(row.artist)) {
+      map.set(row.artist, row.artist_ko);
+    }
Evidence
getArtistKoMapDB()는 정렬 없이 조회한 결과를 순회하며 map.has()로 첫 행만 채택합니다. translationJpn.ts는
dbArtistKoMap.get(song.artist)를 alias 다음 우선순위로 사용해 AI 번역 결과보다 우선 적용합니다.

packages/crawling/src/supabase/getDB.ts[116-137]
packages/crawling/src/cron/translationJpn.ts[31-69]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getArtistKoMapDB()`는 "first-seen" 규칙을 구현하지만 쿼리 결과의 순서가 고정되어 있지 않아(ORDER BY 없음) 동일 artist에 여러 `artist_ko`가 있는 경우 어떤 값이 선택될지 비결정적입니다. 이 Map은 번역 시 AI 결과보다 우선 적용되므로, 실행마다 `artist_ko` 재사용 결과가 달라질 수 있습니다.
### Issue Context
- Map 구성은 `if (!map.has(row.artist)) map.set(...)` 형태로 첫 번째 행을 채택합니다.
- 하지만 Supabase 쿼리에 `.order(...)`가 없어 "첫 번째"의 의미가 불명확합니다.
### Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[121-136]
- packages/crawling/src/cron/translationJpn.ts[61-69]
### Suggested fix
- `getArtistKoMapDB()` 쿼리에 결정적 정렬을 추가하세요(예: `order('artist', { ascending: true })` 후 `order('updated_at', { ascending: true })` 또는 일관성 있는 tie-breaker).
- 가능하면 DB에서 artist 단위로 단일 row를 보장(뷰/RPC/unique constraint)하거나, 어떤 기준(최신/최초)을 채택할지 명시적으로 결정해 쿼리로 강제하세요.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Whitespace artist_ko reused 🐞 Bug ≡ Correctness ⭐ New
Description
getArtistKoMapDB accepts whitespace-only artist_ko values (truthy strings) into dbArtistKoMap, and
translationJpn then prefers that DB value over the AI result via alias ?? db ?? AI, writing the
whitespace into songs.artist_ko. This can propagate “blank” artist translations across subsequent
updates for the same artist.
Code

packages/crawling/src/supabase/getDB.ts[R130-135]

+  const map = new Map<string, string>();
+  for (const row of data) {
+    if (!row.artist || !row.artist_ko) continue;
+    if (!map.has(row.artist)) {
+      map.set(row.artist, row.artist_ko);
+    }
Evidence
Whitespace-only strings are truthy in JS/TS, so if (!row.artist_ko) continue; will not filter
values like '   '. That value can be inserted into the map and then preferred over the AI
translation due to the ?? chain, and finally persisted to the DB without sanitization.

packages/crawling/src/supabase/getDB.ts[116-137]
packages/crawling/src/cron/translationJpn.ts[61-95]
packages/crawling/src/supabase/updateDB.ts[44-58]
packages/crawling/src/utils/translateJpnToKo.ts[10-53]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getArtistKoMapDB()` currently treats whitespace-only `artist_ko` as valid and `translationJpn.ts` will prefer it over AI output, then persist it. This can produce and propagate blank/whitespace artist translations.

## Issue Context
- `if (!row.artist_ko) continue;` only filters `null`/`''`, not `'   '`
- `finalArtistKo = alias ?? db ?? ai` will choose whitespace DB values
- DB update path does not sanitize strings

## Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[121-137]
- packages/crawling/src/cron/translationJpn.ts[61-95]
- packages/crawling/src/supabase/updateDB.ts[44-58]

## Suggested fix
- In `getArtistKoMapDB()`: normalize inputs:
 - `const artist = row.artist?.trim(); const artistKo = row.artist_ko?.trim();`
 - `if (!artist || !artistKo) continue;`
 - Store trimmed values in the map.
- In `translationJpn.ts`: before calling `updateSongKoTranslationDB`, ensure `finalArtistKo.trim()` is non-empty; otherwise fall back to `result.artist_ko` (trimmed) or treat as failure.
- Optionally sanitize in `updateSongKoTranslationDB` as a last line of defense (trim and reject empty).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Artist map capped at 50k 🐞 Bug ☼ Reliability ⭐ New
Description
getArtistKoMapDB hard-limits results to 50,000 rows with no pagination, so it cannot guarantee
loading the full set of translated J-POP artists once the dataset exceeds that size. Additionally,
because there is no explicit ORDER BY, the “first-seen” winner per artist is not well-defined by the
query.
Code

packages/crawling/src/supabase/getDB.ts[R121-127]

+  const { data, error } = await supabase
+    .from('songs')
+    .select('artist, artist_ko, song_tags!inner(tag_id)')
+    .eq('song_tags.tag_id', 101)
+    .not('artist_ko', 'is', null)
+    .limit(50000);
+
Evidence
The function explicitly uses .limit(50000) and does not use .range(...)/pagination, so it will
silently drop rows past the cap. The code’s “first-seen” map semantics depend on row order, but the
query does not specify ordering, so the chosen value is undefined at the SQL level.

packages/crawling/src/supabase/getDB.ts[116-138]
packages/crawling/src/cron/translationJpn.ts[31-70]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getArtistKoMapDB()` is capped at 50k rows and does not specify ordering. This prevents it from reliably representing the full translated artist history and makes the “first-seen” selection not well-defined.

## Issue Context
- Current query: `.limit(50000)` only
- No `.order(...)` and no pagination loop
- The map is used to enforce translation consistency across songs

## Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[121-127]
- packages/crawling/src/supabase/getDB.ts[130-137]

## Suggested fix
- Add a deterministic order for stable results (e.g., order by `artist` then by `id`, or by `updated_at` depending on desired policy).
- Implement pagination using `.range(from, to)` in a loop until an empty page is returned.
- Keep the existing `Map` “first-seen” behavior, but make “first” deterministic via the ORDER BY.
- Consider reducing payload (only select needed columns) and/or selecting distinct artists server-side if supported in your codebase.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Artist map hard-truncated 🐞 Bug ☼ Reliability
Description
getArtistKoMapDB()는 .limit(50000)만 적용하고 페이지네이션이 없어 50,000행을 초과하면 맵이 조용히 누락됩니다. 누락된 artist는
translationJpn.ts에서 DB 재사용이 아닌 AI 결과로 처리되어, PR에서 의도한 ‘DB 전체 기반 일관성’이 깨집니다.
Code

packages/crawling/src/supabase/getDB.ts[R121-126]

+  const { data, error } = await supabase
+    .from('songs')
+    .select('artist, artist_ko, song_tags!inner(tag_id)')
+    .eq('song_tags.tag_id', 101)
+    .not('artist_ko', 'is', null)
+    .limit(50000);
Evidence
getArtistKoMapDB()는 50k 제한만 두고 추가 조회(예: range 기반 반복)가 없으며, 반환된 Map은 translationJpn.ts에서 artist_ko
우선순위 2번으로 사용됩니다. 따라서 조회 대상이 50k를 넘으면 일부 artist가 Map에 들어오지 못해 AI 경로로 폴백합니다.

packages/crawling/src/supabase/getDB.ts[118-138]
packages/crawling/src/cron/translationJpn.ts[31-69]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getArtistKoMapDB()`는 `.limit(50000)`으로만 데이터를 가져오며 페이지네이션이 없어 데이터가 50,000행을 초과할 경우 artist→artist_ko 맵이 불완전해집니다. 그 결과 동일 artist라도 DB 재사용이 누락되어 AI 번역으로 처리될 수 있습니다.
### Issue Context
- 현재 구현은 songs row 단위로 최대 50k만 스캔합니다.
- 맵은 번역 시 우선순위( alias → DB → AI )의 핵심 입력입니다.
### Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[121-137]
### Suggested fix
- `.range(from, to)`를 사용해 페이지네이션 루프를 구현하여 더 이상 데이터가 없을 때까지 모두 로드하세요.
- 또는 DB 쪽에서 artist 단위로 집계/중복제거된 결과(뷰/RPC로 distinct artist)만 내려주도록 바꿔 전송량과 누락 위험을 동시에 제거하세요.
- 최소한 50k에 도달했을 때 경고 로그를 남겨 "조용한 누락"을 관측 가능하게 하세요.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
5. Uncaught preload aborts job 🐞 Bug ☼ Reliability
Description
translationJpn.ts는 getArtistKoMapDB()를 try/catch 밖에서 await하며, getArtistKoMapDB()는 Supabase error를
throw합니다. 이 호출이 실패하면 곡 처리 루프가 시작되기 전에 전체 크론이 즉시 종료됩니다.
Code

packages/crawling/src/cron/translationJpn.ts[R31-34]

+// DB 에 이미 번역된 artist → artist_ko 맵 (동일 아티스트 번역 일관성 유지 목적)
+// DB 는 아티스트당 단일 artist_ko 로 정규화되어 있으며, 번역 성공 시 런타임에도 동기화한다
+const dbArtistKoMap = await getArtistKoMapDB();
+
Evidence
translationJpn.ts는 프리로드 호출을 보호하지 않으며, getArtistKoMapDB()는 if (error) throw error로 예외를 전파합니다. 따라서
프리로드 단계에서 오류가 발생하면 이후 번역 처리 자체가 실행되지 않습니다.

packages/crawling/src/cron/translationJpn.ts[27-35]
packages/crawling/src/supabase/getDB.ts[118-129]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getArtistKoMapDB()` 프리로드가 실패하면 예외가 전파되어 번역 크론 전체가 시작 전에 중단됩니다.
### Issue Context
- `getArtistKoMapDB()`는 Supabase 에러 시 throw 합니다.
- `translationJpn.ts`는 해당 호출을 try/catch로 감싸지 않습니다.
### Fix Focus Areas
- packages/crawling/src/cron/translationJpn.ts[31-34]
- packages/crawling/src/supabase/getDB.ts[121-129]
### Suggested fix
- `translationJpn.ts`에서 `getArtistKoMapDB()`를 try/catch로 감싸고, 실패 시 `new Map()`으로 폴백한 뒤 경고 로그를 남기세요.
- (선택) 재시도/백오프를 추가하거나, 프리로드 실패 시에도 AI 번역 경로로 최소 기능이 동작하도록 보장하세요.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 19, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Non-deterministic artist_ko pick 🐞 Bug ≡ Correctness
Description
getArtistKoMapDB()는 Map에 first-seen으로 artist_ko를 고정하지만 쿼리에 ORDER BY가 없어 동일 artist에 여러 artist_ko가 존재할
때 어떤 값이 선택될지 실행마다 달라질 수 있습니다. 이 값은 translationJpn.ts에서 AI 결과를 덮어써 artist_ko 재사용 일관성을 깨뜨릴 수 있습니다.
Code

packages/crawling/src/supabase/getDB.ts[R121-135]

+  const { data, error } = await supabase
+    .from('songs')
+    .select('artist, artist_ko, song_tags!inner(tag_id)')
+    .eq('song_tags.tag_id', 101)
+    .not('artist_ko', 'is', null)
+    .limit(50000);
+
+  if (error) throw error;
+
+  const map = new Map<string, string>();
+  for (const row of data) {
+    if (!row.artist || !row.artist_ko) continue;
+    if (!map.has(row.artist)) {
+      map.set(row.artist, row.artist_ko);
+    }
Evidence
getArtistKoMapDB()는 정렬 없이 조회한 결과를 순회하며 map.has()로 첫 행만 채택합니다. translationJpn.ts는
dbArtistKoMap.get(song.artist)를 alias 다음 우선순위로 사용해 AI 번역 결과보다 우선 적용합니다.

packages/crawling/src/supabase/getDB.ts[116-137]
packages/crawling/src/cron/translationJpn.ts[31-69]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getArtistKoMapDB()`는 "first-seen" 규칙을 구현하지만 쿼리 결과의 순서가 고정되어 있지 않아(ORDER BY 없음) 동일 artist에 여러 `artist_ko`가 있는 경우 어떤 값이 선택될지 비결정적입니다. 이 Map은 번역 시 AI 결과보다 우선 적용되므로, 실행마다 `artist_ko` 재사용 결과가 달라질 수 있습니다.

### Issue Context
- Map 구성은 `if (!map.has(row.artist)) map.set(...)` 형태로 첫 번째 행을 채택합니다.
- 하지만 Supabase 쿼리에 `.order(...)`가 없어 "첫 번째"의 의미가 불명확합니다.

### Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[121-136]
- packages/crawling/src/cron/translationJpn.ts[61-69]

### Suggested fix
- `getArtistKoMapDB()` 쿼리에 결정적 정렬을 추가하세요(예: `order('artist', { ascending: true })` 후 `order('updated_at', { ascending: true })` 또는 일관성 있는 tie-breaker).
- 가능하면 DB에서 artist 단위로 단일 row를 보장(뷰/RPC/unique constraint)하거나, 어떤 기준(최신/최초)을 채택할지 명시적으로 결정해 쿼리로 강제하세요.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Artist map hard-truncated 🐞 Bug ☼ Reliability
Description
getArtistKoMapDB()는 .limit(50000)만 적용하고 페이지네이션이 없어 50,000행을 초과하면 맵이 조용히 누락됩니다. 누락된 artist는
translationJpn.ts에서 DB 재사용이 아닌 AI 결과로 처리되어, PR에서 의도한 ‘DB 전체 기반 일관성’이 깨집니다.
Code

packages/crawling/src/supabase/getDB.ts[R121-126]

+  const { data, error } = await supabase
+    .from('songs')
+    .select('artist, artist_ko, song_tags!inner(tag_id)')
+    .eq('song_tags.tag_id', 101)
+    .not('artist_ko', 'is', null)
+    .limit(50000);
Evidence
getArtistKoMapDB()는 50k 제한만 두고 추가 조회(예: range 기반 반복)가 없으며, 반환된 Map은 translationJpn.ts에서 artist_ko
우선순위 2번으로 사용됩니다. 따라서 조회 대상이 50k를 넘으면 일부 artist가 Map에 들어오지 못해 AI 경로로 폴백합니다.

packages/crawling/src/supabase/getDB.ts[118-138]
packages/crawling/src/cron/translationJpn.ts[31-69]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getArtistKoMapDB()`는 `.limit(50000)`으로만 데이터를 가져오며 페이지네이션이 없어 데이터가 50,000행을 초과할 경우 artist→artist_ko 맵이 불완전해집니다. 그 결과 동일 artist라도 DB 재사용이 누락되어 AI 번역으로 처리될 수 있습니다.

### Issue Context
- 현재 구현은 songs row 단위로 최대 50k만 스캔합니다.
- 맵은 번역 시 우선순위( alias → DB → AI )의 핵심 입력입니다.

### Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[121-137]

### Suggested fix
- `.range(from, to)`를 사용해 페이지네이션 루프를 구현하여 더 이상 데이터가 없을 때까지 모두 로드하세요.
- 또는 DB 쪽에서 artist 단위로 집계/중복제거된 결과(뷰/RPC로 distinct artist)만 내려주도록 바꿔 전송량과 누락 위험을 동시에 제거하세요.
- 최소한 50k에 도달했을 때 경고 로그를 남겨 "조용한 누락"을 관측 가능하게 하세요.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Uncaught preload aborts job 🐞 Bug ☼ Reliability
Description
translationJpn.ts는 getArtistKoMapDB()를 try/catch 밖에서 await하며, getArtistKoMapDB()는 Supabase error를
throw합니다. 이 호출이 실패하면 곡 처리 루프가 시작되기 전에 전체 크론이 즉시 종료됩니다.
Code

packages/crawling/src/cron/translationJpn.ts[R31-34]

+// DB 에 이미 번역된 artist → artist_ko 맵 (동일 아티스트 번역 일관성 유지 목적)
+// DB 는 아티스트당 단일 artist_ko 로 정규화되어 있으며, 번역 성공 시 런타임에도 동기화한다
+const dbArtistKoMap = await getArtistKoMapDB();
+
Evidence
translationJpn.ts는 프리로드 호출을 보호하지 않으며, getArtistKoMapDB()는 if (error) throw error로 예외를 전파합니다. 따라서
프리로드 단계에서 오류가 발생하면 이후 번역 처리 자체가 실행되지 않습니다.

packages/crawling/src/cron/translationJpn.ts[27-35]
packages/crawling/src/supabase/getDB.ts[118-129]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getArtistKoMapDB()` 프리로드가 실패하면 예외가 전파되어 번역 크론 전체가 시작 전에 중단됩니다.

### Issue Context
- `getArtistKoMapDB()`는 Supabase 에러 시 throw 합니다.
- `translationJpn.ts`는 해당 호출을 try/catch로 감싸지 않습니다.

### Fix Focus Areas
- packages/crawling/src/cron/translationJpn.ts[31-34]
- packages/crawling/src/supabase/getDB.ts[121-129]

### Suggested fix
- `translationJpn.ts`에서 `getArtistKoMapDB()`를 try/catch로 감싸고, 실패 시 `new Map()`으로 폴백한 뒤 경고 로그를 남기세요.
- (선택) 재시도/백오프를 추가하거나, 프리로드 실패 시에도 AI 번역 경로로 최소 기능이 동작하도록 보장하세요.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

PR Description updated to latest commit (9c13385)

Comment on lines +121 to +135
const { data, error } = await supabase
.from('songs')
.select('artist, artist_ko, song_tags!inner(tag_id)')
.eq('song_tags.tag_id', 101)
.not('artist_ko', 'is', null)
.limit(50000);

if (error) throw error;

const map = new Map<string, string>();
for (const row of data) {
if (!row.artist || !row.artist_ko) continue;
if (!map.has(row.artist)) {
map.set(row.artist, row.artist_ko);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Non-deterministic artist_ko pick 🐞 Bug ≡ Correctness

getArtistKoMapDB()는 Map에 first-seen으로 artist_ko를 고정하지만 쿼리에 ORDER BY가 없어 동일 artist에 여러 artist_ko가 존재할
때 어떤 값이 선택될지 실행마다 달라질 수 있습니다. 이 값은 translationJpn.ts에서 AI 결과를 덮어써 artist_ko 재사용 일관성을 깨뜨릴 수 있습니다.
Agent Prompt
### Issue description
`getArtistKoMapDB()`는 "first-seen" 규칙을 구현하지만 쿼리 결과의 순서가 고정되어 있지 않아(ORDER BY 없음) 동일 artist에 여러 `artist_ko`가 있는 경우 어떤 값이 선택될지 비결정적입니다. 이 Map은 번역 시 AI 결과보다 우선 적용되므로, 실행마다 `artist_ko` 재사용 결과가 달라질 수 있습니다.

### Issue Context
- Map 구성은 `if (!map.has(row.artist)) map.set(...)` 형태로 첫 번째 행을 채택합니다.
- 하지만 Supabase 쿼리에 `.order(...)`가 없어 "첫 번째"의 의미가 불명확합니다.

### Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[121-136]
- packages/crawling/src/cron/translationJpn.ts[61-69]

### Suggested fix
- `getArtistKoMapDB()` 쿼리에 결정적 정렬을 추가하세요(예: `order('artist', { ascending: true })` 후 `order('updated_at', { ascending: true })` 또는 일관성 있는 tie-breaker).
- 가능하면 DB에서 artist 단위로 단일 row를 보장(뷰/RPC/unique constraint)하거나, 어떤 기준(최신/최초)을 채택할지 명시적으로 결정해 쿼리로 강제하세요.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@GulSam00 GulSam00 merged commit 721e16e into develop Apr 19, 2026
2 checks passed
@GulSam00 GulSam00 deleted the refactor/199-refactorDbArtistKoMapInit branch April 19, 2026 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: J-POP 번역 스크립트 dbArtistKoMap 초기화를 DB 직접 조회로 변경

1 participant